阅读更多

0顶
0踩

移动开发

转载新闻 使用Swift原生库解析XML数据

2015-12-17 17:55 by 副主编 mengyidan1988 评论(1) 有7006人浏览
在实现文件操作的时候我意识到了一个事实:由于NSURL是可支持的路径,很多文件的操作实际上可以扩充到网络上去,比如从网上下载一个文件、拿取一些数据……想到这里,埋藏在心中很久的愿望又开始蠢蠢欲动:写一个新闻客户端!
我有一个常看的新闻网站(不要问我是哪个,要FQ),官方客户端很难用,第三方广告满天飞,严重影响心情。所以当初开始学iOS的时候就把重做一个客户端的目标放在了首位。最开始的时候想得太简单,兴冲冲地开了个project,搞了两下TableView,然后发现……对于我这种从来只写底层代码,swift/OC语法都不会的人,做这个简直是异想天开好嘛!
折腾的过程中,为了拿到数据,还跑去下了Android的官方客户端反编译,find + grep出来了人家的数据接口地址(论一个爱折腾的程序员是怎么给自己挖坑的),返回的是XML数据,连蒙带猜试了试,可以用!不过后来做UI受挫(其实不止做UI,挫败感太大),就把那份东西闲置起来了。这两天突然想起来,现在我貌似感觉有点良好,何不捡起来继续写我的客户端?
因为UI我还一窍不通,不懂怎么调试,也不懂怎么把数据显示出来,为了避免到处打印的麻烦,我选择playground。这样也就是需要用原生库,这个很简单,搜一下就有了:NSXMLParserDelegate,还有好些源码,虽然大多是OC的。
问题是有源码,我依!然!看!不!懂!怎么用!每个教程都是扔了源码上来,可没人解释清楚到底怎么运行。我研究了好一阵,终于明白了大概的机制:
引用
自己写一个类继承NSXMLParserDelegate,就叫它XmlReader吧;并且实现一些必须的callback函数,在XmlReader的Init中调用.parse()方法,最后在new XmlReader的时候就会自动完成整个parse了

当然你也可以不把parse()放在init()中调用,而是在new了XmlReader之后强制调用,重要的是那些callback函数的实现。XmlReader中还可以声明一些变量,来保存解析过程中的状态,而具体的获得到的数据填充,也是需要你自己做的(数据结构自行定义)。
鉴于XML是一个有层级的带递归意味的数据结构,程序会层层解析下去直到结束,中间遇到的各种类似section开始、结束、拿到字符串等情况都会call一个固定的函数,将解析出来的数据作为参数传进去,而你要做的,就是实现这些callback以完成自己想要做的事。
下面是具体的代码示范。首先是定义一个新的类:
class XmlReader: NSObject, NSXMLParserDelegate {
var currentName :String? = nil
var level :Int = 0

 init(add :String ) {

    super.init()
    let url = NSURL(string:add)!
    guard let parserXML = NSXMLParser(contentsOfURL: url) else {
        return
    }

    parserXML.delegate = self
    parserXML.parse()
    }

func parserDidStartDocument(parser: NSXMLParser) {}

func parserDidEndDocument(parser: NSXMLParser){}

func parser(parser: NSXMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String]) {}

func parser(parser: NSXMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {}

func parser(parser: NSXMLParser, var foundCharacters string: String) {}

func parser(parser: NSXMLParser, parseErrorOccurred parseError: NSError) {}
}

这是一个基础部分,里面定义了一些callback但没有实现它。我把xml的地址作为参数传给了init(),并且声明了两个变量currentName和level分别用来保存当前的标签名字和递归深度。然后我们基于下面这个简单的XML文件继续完成callback部分:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<language cat="it">
    <lan id="1">
        <name>C#</name>
        <IDE>vs</IDE>
    </lan>
    <lan id="2" />
</language>

首先是文档开始和结束时:
//文档开始解析时触发,只触发一次
func parserDidStartDocument(parser: NSXMLParser) {
    print("    start")
}

//文档结束时触发,只触发一次,通常需要在这里给出一个信号告诉上层或其他人解析已经结束
func parserDidEndDocument(parser: NSXMLParser){
    print("    end")
}

然后是标签的开始和结束事件:
//遇到一个开始标签触发,elementName为当前标签,如果当前标签有属性,则字典sttributeDict不为空
func parser(parser: NSXMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String]()) {
    self.currentName = elementName
    self.level++
    print("\(level) start, \(elementName), \(attributeDict)")
    if currentName == "language" { // 获取language属性的内容
        //print("language: \(attributeDict)")
    }
}

//遇到结束标签触发,该方法主要是做一些清理工作,在这里我修改了当前的深度
func parser(parser: NSXMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
    print("\(level) end, \(elementName)")
    self.currentName = nil
    self.level--
}

接下来是字符串值的handler
// 遇到字符串时触发
func parser(parser: NSXMLParser, var foundCharacters string: String) {
    //删除首尾的回车符和空格
    string = string.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet())
    if string.isEmpty {
        return
    }
    print("---- \(string)")
}

最后是Error Handler
// 文档出错时触发
func parser(parser: NSXMLParser, parseErrorOccurred parseError: NSError) {
    print(parseError)
}

以上的callback函数实现都只放了些打印信息,在实际操作中需要把这些获取的信息一一填充进自己的数据结构中。说实话是挺麻烦的,难怪都说XML快要被JSON全面取代(其实对于曾被libxml折磨过的码农来说,这已经挺好了)。全部的代码传送门:这里

本文转自:http://conanwhf.gitcafe.io/
0
0
评论 共 1 条 请登录后发表评论
1 楼 YiBuXiaoCai 2015-12-18 10:15
程序员群 2177712 

发表评论

您还没有登录,请您登录后再发表评论

相关推荐

  • Swift 原生Xml解析

    XMLParser解析 1.XML数据 &lt;?xml version="1.0" encoding="UTF-8" standalone="no"?&gt; &lt;person id="1"&gt; &lt;name&gt;xiaopao&lt;/name&gt; &lt;age&gt;21&lt;/age&gt; &lt;/person&gt; ...

  • SwiftUI学习笔记【XML解析】

    对于接触过IOS解析XML的应该很多吧…我是写Android的我司项目会涉及到很多xml解析导出给CAD然后CAD解析完成之后进行绘制编辑等。原生Android有很多对于XML的解析方式[SAX,Pull,DOM等],Flutter的对于XML解析很少了...

  • iOS XML数据解析

    最近公司的活比较少,空闲时间...在这个过程中便有使用到XML数据,于是研究了一下。目前写的这个是本地阅读软件,后续会把在写这个APP用到的技术以及遇到的问题都整理出来,通过博客的形式分享给大家。奇迹读书地址。

  • iOS开发之Swift 4 JSON 解析指南

    Apple 终于在 Swift 4 的 Foundation 的模块中添加了对 JSON 解析的原生支持。 虽然已经有很多第三方类库实现了 JSON 解析,但是能够看到这样一个功能强大、易于使用的官方实现还是不免有些兴奋。 值得注意的是,...

  • Swift4 JSON解析指南

    Apple 终于在 Swift 4 的 Foundation 的模块中添加了对 JSON 解析的原生支持。 虽然已经有很多第三方类库实现了 JSON 解析,但是能够看到这样一个功能强大、易于使用的官方实现还是不免有些兴奋。 值得注意的是,...

  • Swift 4 JSON 解析指南

    Apple 终于在 Swift 4 的 Foundation 的模块中添加了对 JSON 解析的原生支持。 虽然已经有很多第三方类库实现了 JSON 解析,但是能够看到这样一个功能强大、易于使用的官方实现还是不免有些兴奋。 值得注意的是,...

  • iOS开发最常用三方库集合Swift版(三方库、插件、博客等等)

    Swift学习资料@SwiftGuide很赞 的Swift学习资料leetcode一个练习、评估自己水平的代码平台,跟ACM有点类似完整App@Swift 30 Projects- 最新 Swift 3.0 的30个小App,更注重代码规范和架构设计(故胤道长)V2ex-Swift- ...

  • model存储 swift_iOS ~ Swift之数据存储(.plist,NSUserDefaults,NSKeyedArchiver)

    最近公司项目中使用了本地存储,所以趁着周六日来整理一下在Swift中的几种数据存储方式。一、plist文件存储存储目录:Documents每次在Xcode中新建一个iOS项目后,都会自己产生一个.plist文件,里面记录项目的一些...

  • 读取与解析json类型数据

    读取与解析json类型数据 一、什么是JSON? JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式,采用完全独立于语言的文本格式, 是理想的数据交换格式,同时,JSON是 JavaScript 原生格式。 非常...

  • RAG知识库问答LangChain+LLM的二次开发:商用时的典型问题及其改进方案

    如之前的文章所述,我司下半年成立大模型项目团队之后,我兼管整个项目团队,但为让项目的推进效率更高,故分成了三大项目组对于知识库问答,现在有两种方案,一种基于llamaindex,一种基于langchain +LLM,考虑到我...

  • 强烈推荐大家看这篇文章:iOS开发常用三方库、插件、知名博客等等(特别有用)

    Swift版本点击这里欢迎加入交QQ流群: 594119878github排名 https://github.com/trending,github搜索:https://github.com/search使用方法:根据目录关键字搜索,记得包含@,以保证搜索目录关键字的唯一性。...

  • iOS之网络—— JSON解析、XML解析、文件下载、文件的压缩和解压缩

    (2)服务器返回给客户端的数据,一般都是JSON格式或者XML格式(文件下载除外) 002 相关说明 (1)JSON的格式很像OC中的字典和数组 (2)标准JSON格式key必须是双引号 003 JSON解析方案

  • 安装NumPy教程-详细版

    附件是安装NumPy教程_详细版,文件绿色安全,请大家放心下载,仅供交流学习使用,无任何商业目的!

  • 语音端点检测及其在Matlab中的实现.zip

    语音端点检测及其在Matlab中的实现.zip

  • C#文档打印程序Demo

    使用C#完成一般文档的打印,带有页眉,页脚文档打印,表格打印,打印预览等

  • DirectX修复工具-4-194985.zip

    directx修复工具 DirectX修复工具(DirectX repair)是系统DirectX组件修复工具,DirectX修复工具主要是用于检测当前系统的DirectX状态,若发现异常情况就可以马上进行修复,非常快捷,使用效果也非常好。

  • Python手动实现人脸识别算法

    人脸识别的主要算法 其核心算法是 欧式距离算法使用该算法计算两张脸的面部特征差异,一般在0.6 以下都可以被认为是同一张脸 人脸识别的主要步骤 1 获得人脸图片 2 将人脸图片转为128D的矩阵(这个也就是人脸特征的一种数字化表现) 3 保存人脸128D的特征到文件中 4 获取其他人脸转为128D特征通过欧式距离算法与我们保存的特征对比,如果差距在0.6以下就说明两张脸差距比较小

  • 全国大学生信息安全竞赛知识问答-CISCN 题库.zip

    ciscn 全国大学生信息安全竞赛知识问答-CISCN 题库.zip

  • JAVA+SQL离散数学题库管理系统(源代码+LW+外文翻译).zip

    JAVA+SQL离散数学题库管理系统(源代码+LW+外文翻译)JAVA+SQL离散数学题库管理系统(源代码+LW+外文翻译)JAVA+SQL离散数学题库管理系统(源代码+LW+外文翻译)JAVA+SQL离散数学题库管理系统(源代码+LW+外文翻译)JAVA+SQL离散数学题库管理系统(源代码+LW+外文翻译)JAVA+SQL离散数学题库管理系统(源代码+LW+外文翻译)JAVA+SQL离散数学题库管理系统(源代码+LW+外文翻译)JAVA+SQL离散数学题库管理系统(源代码+LW+外文翻译)JAVA+SQL离散数学题库管理系统(源代码+LW+外文翻译)JAVA+SQL离散数学题库管理系统(源代码+LW+外文翻译)JAVA+SQL离散数学题库管理系统(源代码+LW+外文翻译)JAVA+SQL离散数学题库管理系统(源代码+LW+外文翻译)JAVA+SQL离散数学题库管理系统(源代码+LW+外文翻译)JAVA+SQL离散数学题库管理系统(源代码+LW+外文翻译)

  • strcmp函数应用.zip

    strcmp函数应用.zip

Global site tag (gtag.js) - Google Analytics